/*
 * CDollSlot.java
 *
 * Copyright (c) 2009 Giles Millward (Manigra). All rights reserved.
 *
 * This file is part of JRogueDPS.
 *
 * JRogueDPS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * JRogueDPS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with JRogueDPS.  If not, see <http://www.gnu.org/licenses/>.
 */

package paperdoll;

import geardatabase.CItem;
import geardatabase.CGemType;
import geardatabase.CGemType.GemType;
import geardatabase.CItemQuality;
import geardatabase.CItemType.ItemType;
import geardatabase.CSocketHolder;
import java.awt.Color;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import jroguedps.CGlobal;
import org.dom4j.Element;
import org.dom4j.Node;
import paperdoll.CDollSlotType.DollSlotType;
import paperdoll.CItemChooser.ChooserType;

/**
 *
 * @author Mani
 */
public class CDollSlot {

    Color m_itemBackground = Color.LIGHT_GRAY;
    Color m_enchantBackground = new Color(128,215,128);
    Color m_poisonBackground = new Color(215,215,128);
    Color m_blacksmithBackground = new Color(230,230,230);
    Color m_badGemBackground = new Color(247,220,220);
    Color m_metaBrokenColor = new Color(215, 128, 128);

    String m_name;
    // Slot for this item
    DollSlotType m_slotType = null;
    int m_rowOffset;
    // Item class itself
    CItem m_itemId = null;
    CItem m_enchantId = null;
    CItem m_poisonId = null;
    CItem m_blacksmithGem = null;
    CItem m_beltBuckleGem = null;
    // Enchant for this item
    boolean m_enchantable;
    boolean m_poisonable = false;
    boolean m_blacksmith = false;

    int m_meta_red_required = 0;
    int m_meta_yellow_required = 0;
    int m_meta_blue_required = 0;

    // Expandable gem list;
    ArrayList<CItem> m_gemList = new ArrayList<CItem>();

    CDollSlot(String p_name, DollSlotType p_slotType, int p_rowOffset, boolean p_enchantable)
    {
        m_name = p_name;
        m_slotType = p_slotType;
        m_rowOffset = p_rowOffset;
        m_enchantable = p_enchantable;
        if (p_slotType == DollSlotType.MAINHAND || p_slotType == DollSlotType.OFFHAND)
        {
            m_poisonable = true;
        }

        if (p_slotType == DollSlotType.HANDS || p_slotType == DollSlotType.WRIST)
        {
            m_blacksmith = true;
        }
    }

    public CItem getItem()
    {
        return m_itemId;
    }
    
    void setItem(CItem p_item)
    {
        m_itemId = p_item;
        m_gemList.clear();
        m_meta_red_required = 0;
        m_meta_yellow_required = 0;
        m_meta_blue_required = 0;
        CItem l_nullItem = CGlobal.g_database.getItem("0");
        for (int i = 0; i < m_itemId.getNumberOfSockets(); i++)
        {
            // Default gems to 'none'
            m_gemList.add(l_nullItem);
        }
    }

    void setEnchant(CItem p_enchantItem)
    {
        if (m_enchantable)
        {
            m_enchantId = p_enchantItem;
        }
    }

    public CItem getEnchant()
    {
        if (m_enchantable)
        {
            return m_enchantId;
        }

        return null;
    }

    void setGem(CItem m_gemId, int p_index)
    {
        if (this.m_slotType == DollSlotType.HEAD)
        {
            if (m_gemId.getGemType() == GemType.META)
            {
                // Workout from tooltip the metagem requirements
                m_meta_red_required = this.getMetaRequirement(m_gemId, "Red");
                m_meta_yellow_required = this.getMetaRequirement(m_gemId, "Yellow");
                m_meta_blue_required = this.getMetaRequirement(m_gemId, "Blue");
            }
        }
        
        if (p_index < m_itemId.getNumberOfSockets())
        {
            // Normal slots
            this.m_gemList.set(p_index, m_gemId);
        }
    }

    public int getMetaGem()
    {
        if (this.m_slotType != DollSlotType.HEAD)
        {
            return 0;
        }

        if (this.m_meta_blue_required == 0 &&
                this.m_meta_red_required == 0 &&
                this.m_meta_yellow_required == 0)
        {
            return 0;
        }

        return this.m_gemList.get(0).getId();
    }
    
    private int getMetaRequirement(CItem p_gemId, String p_color)
    {
            Pattern pattern = Pattern.compile("least \\d " + p_color + " gem");

            // Check for the existence of the pattern
            Matcher l_matcher = pattern.matcher(p_gemId.getHtmlTooltip());
            if (l_matcher.find())
            {
                return Integer.parseInt(l_matcher.group().substring(6,7));
            }

            return 0;
    }

    void setBSGem(CItem m_gemId)
    {
        this.m_blacksmithGem = m_gemId;
    }

    void setBBGem(CItem m_gemId)
    {
        this.m_beltBuckleGem = m_gemId;
    }

    void setPoison(CItem p_poisonItem)
    {
        if (m_poisonable)
        {
            m_poisonId = p_poisonItem;
        }
    }

    public CItem getPoison()
    {
        return m_poisonId;
    }
    
    // Work out if socket bonus is active
    boolean socketBonus()
    {
        boolean l_foundGem = false;

        for (int i = 0; i < this.m_gemList.size(); i++)
        {
            CItem l_gem = this.m_gemList.get(i);
            CSocketHolder l_socket = this.m_itemId.getSocketHolder(i);
            if (!CGemType.matchGem(l_socket.getSocketType(), l_gem.getGemType()))
            {
                return false;
            }
            else
            {
                l_foundGem = true;
            }
        }
        
        return l_foundGem;
    }
    // User double clicked on some part of this slot so we need to create an item
    // chooser but first we need to know the ChooserType
    void itemChooser(int y_offset)
    {
        int y = y_offset - m_rowOffset;
        
        if (y == 0)
        {
            // Slot item name guaranteed at this position
            CItem l_item = new CItemChooser(CGlobal.g_jFrame, this.m_slotType, ChooserType.ITEM,
                                              CGlobal.g_paperDoll.m_gemQualityFilter,
                                              CGlobal.g_paperDoll.m_itemQualityFilter).getValue();

            if (l_item == null)
            {
                // User hit cancel
                return;
            }

            CGlobal.g_paperDoll.setItem(l_item, m_slotType);
            return;
        }

        // Item enchants
        if (y == 1 && m_enchantable)
        {
            CItem l_item = new CItemChooser(CGlobal.g_jFrame, this.m_slotType, ChooserType.ENCHANT,
                                              CGlobal.g_paperDoll.m_gemQualityFilter,
                                              CGlobal.g_paperDoll.m_itemQualityFilter).getValue();
            if (l_item == null)
            {
                // User hit cancel
                return;
            }

            CGlobal.g_paperDoll.setEnchant(l_item, m_slotType);
            if (l_item.getId() == 3722)
            {
                CGlobal.g_paperDoll.setBBGem(CGlobal.g_database.getItem("0"), m_slotType);
            }
            return;
        }

        // Weapon poisons
        if (y == 2 && m_poisonable)
        {
            CItem l_item = new CItemChooser(CGlobal.g_jFrame, this.m_slotType, ChooserType.POISON,
                                              CGlobal.g_paperDoll.m_gemQualityFilter,
                                              CGlobal.g_paperDoll.m_itemQualityFilter).getValue();
            if (l_item == null)
            {
                // User hit cancel
                return;
            }

            CGlobal.g_paperDoll.setPoison(l_item, m_slotType);
            return;
        }

        if (y == 5 && m_blacksmith)
        {
            // Blacksmithing Gem
            CItem l_item = new CItemChooser(CGlobal.g_jFrame, this.m_slotType, ChooserType.GEM,
                    CGlobal.g_paperDoll.m_gemQualityFilter,
                    CGlobal.g_paperDoll.m_itemQualityFilter).getValue();
            if (l_item == null) {
                // User hit cancel
                return;
            }

            CGlobal.g_paperDoll.setBSGem(l_item, m_slotType);
            CGlobal.g_paperDoll.refreshTable();
            return;
        }

        if (y == 5 && this.m_slotType == DollSlotType.WAIST &&
                this.m_enchantId != null &&
                this.m_enchantId.getId() == 3722)
        {
            // Eternal belt buckle attached
            // Blacksmithing Gem
            CItem l_item = new CItemChooser(CGlobal.g_jFrame, this.m_slotType, ChooserType.GEM,
                    CGlobal.g_paperDoll.m_gemQualityFilter,
                    CGlobal.g_paperDoll.m_itemQualityFilter).getValue();
            if (l_item == null) {
                // User hit cancel
                return;
            }

            CGlobal.g_paperDoll.setBBGem(l_item, m_slotType);
            CGlobal.g_paperDoll.refreshTable();
            return;
        }

        // y >= 1 so far get socket holder list
        int l_noOfSockets = m_itemId.getNumberOfSockets();
        if (l_noOfSockets != 0)
        {
            if (this.m_enchantable)
            {
                y--;
            }

            if (this.m_poisonable)
            {
                y--;
            }

            y--;
            if (y < l_noOfSockets) {
                ChooserType l_chooserType = ChooserType.GEM;

                if (this.m_itemId.getSocketHolder(y).getSocketType() == GemType.META) {
                    l_chooserType = ChooserType.META;
                }

                CItem l_item = new CItemChooser(CGlobal.g_jFrame, this.m_slotType, l_chooserType,
                        CGlobal.g_paperDoll.m_gemQualityFilter,
                        CGlobal.g_paperDoll.m_itemQualityFilter).getValue();
                if (l_item == null) {
                    // User hit cancel
                    return;
                }

                CGlobal.g_paperDoll.setGem(l_item, this.m_slotType, y);
                CGlobal.g_paperDoll.refreshTable();
                return;
            }
        }

    }

    // Render a cell in this doll slot (Could be item name, gems, enchant etc)
    void renderCell(CDollRenderer p_renderer,int x, int y_offset)
    {
        int y = y_offset - m_rowOffset;

        p_renderer.setToolTipText("");
        p_renderer.setText("");
        p_renderer.setBackground(Color.WHITE);
        p_renderer.setForeground(Color.BLACK);
        p_renderer.setIcon(null);

        if (y == 0)
        {
            if (x == 0)
            {
                p_renderer.setForeground(Color.BLACK);
                p_renderer.setText(m_name);
                p_renderer.setBackground(m_itemBackground);
                return;
            } else
            {
                if (m_itemId == null)
                {
                    p_renderer.setText("None");
                    p_renderer.setBackground(Color.WHITE);
                    return;
                }
                else
                {
                    // Set item name and background gear quality color
                    if (m_itemId.getItemType() == ItemType.DAGGER ||
                            m_itemId.getItemType() == ItemType.FIST ||
                            m_itemId.getItemType() == ItemType.MACE ||
                            m_itemId.getItemType() == ItemType.SWORD ||
                            m_itemId.getItemType() == ItemType.AXE)
                    {
                        p_renderer.setText(m_itemId.getName() + " (" + m_itemId.getItemType() + " " + m_itemId.getWeaponSpeed() + ")");
                    }
                    else
                    {
                        p_renderer.setText(m_itemId.getName());
                    }

                    p_renderer.setBackground(CItemQuality.getBackColor(m_itemId.getGearQuality()));
                    p_renderer.setToolTipText("<html>" + m_itemId.getHtmlTooltip() + "</html>");
                    return;
                }
            }
        } else if (y == 1 && m_enchantable)
        {
            if (x == 0 )
            {
                p_renderer.setText("Enchant");
                p_renderer.setBackground(m_enchantBackground);
                return;
            }
            else
            {
                if (this.m_enchantId == null)
                {
                    p_renderer.setText("None");
                    p_renderer.setBackground(Color.WHITE);
                    return;
                }
                else
                {
                    p_renderer.setText(this.m_enchantId.getName());
                    p_renderer.setBackground(Color.WHITE);
                    return;
                }
            }
        } else if (y == 2 && this.m_poisonable)
        {
            if (x == 0 )
            {
                p_renderer.setText("Poison");
                p_renderer.setBackground(m_poisonBackground);
                return;
            }
            else
            {
                if (this.m_poisonId == null)
                {
                    p_renderer.setText("None");
                    p_renderer.setBackground(Color.WHITE);
                    return;
                }
                else
                {
                    p_renderer.setText(m_poisonId.getName());
                    p_renderer.setBackground(Color.WHITE);
                    return;
                }
            }
        }

        if (y == 5 && m_blacksmith)
        {
            // Blacksmithing Gem
            if (x == 0)
            {
                p_renderer.setText("Blacksmith Gem");
                p_renderer.setBackground(m_blacksmithBackground);
                return;
            }

            if (this.m_blacksmithGem != null)
            {
                p_renderer.setText(this.m_blacksmithGem.getName() + " " + this.m_blacksmithGem.getItemStats().getNonZeroStatsString());
                p_renderer.setIcon(CGemType.getGemImage(this.m_blacksmithGem.getGemType()));
                p_renderer.setBackground(CItemQuality.getBackColor(this.m_blacksmithGem.getGearQuality()));
                return;
            }

            return;
        }

        if (y == 5 && this.m_slotType == DollSlotType.WAIST &&
                this.m_enchantId != null &&
                this.m_enchantId.getId() == 3722)
        {
            // Eternal belt buckle attached
            if (x == 0)
            {
                p_renderer.setText("Eternal Belt Buckle Gem");
                p_renderer.setBackground(m_blacksmithBackground);
                return;
            }

            if (this.m_beltBuckleGem != null)
            {
                p_renderer.setText(this.m_beltBuckleGem.getName() + " " + this.m_beltBuckleGem.getItemStats().getNonZeroStatsString());
                p_renderer.setIcon(CGemType.getGemImage(this.m_beltBuckleGem.getGemType()));
                p_renderer.setBackground(CItemQuality.getBackColor(this.m_beltBuckleGem.getGearQuality()));
                return;
            }

            return;
        }

        // y >= 1 so far get socket holder list
        int l_noOfSockets = m_itemId.getNumberOfSockets();
        if (l_noOfSockets != 0)
        {
            if (this.m_enchantable)
            {
                y--;
            }

            if (this.m_poisonable)
            {
                y--;
            }
            
            y--;
            if (y < l_noOfSockets)
            {
                if (x == 0)
                {
                    GemType l_gemType = m_itemId.getSocketHolder(y).getSocketType();
                    if (l_gemType == GemType.META)
                    {
                        // Work out meta gem requirements
                        int l_totalRed = CGlobal.g_paperDoll.getTotalGems(GemType.RED);
                        int l_totalBlue = CGlobal.g_paperDoll.getTotalGems(GemType.BLUE);
                        int l_totalYellow = CGlobal.g_paperDoll.getTotalGems(GemType.YELLOW);

                        if (l_totalRed < this.m_meta_red_required ||
                            l_totalBlue < this.m_meta_blue_required ||
                            l_totalYellow < this.m_meta_yellow_required)
                        {
                            // Broken meta gem
                            String l_report = "";
                            if (l_totalRed < this.m_meta_red_required)
                            {
                                l_report = "Red";
                            }

                            if (l_totalBlue < this.m_meta_blue_required)
                            {
                                if (l_report.equals(""))
                                {
                                    l_report = "Blue";
                                }
                                else
                                {
                                    l_report += "/Blue";
                                }
                            }

                            if (l_totalYellow < this.m_meta_yellow_required)
                            {
                                if (l_report.equals(""))
                                {
                                    l_report = "Yellow";
                                }
                                else
                                {
                                    l_report += "/Yellow";
                                }
                            }

                            l_report += " Broken";
                            p_renderer.setText(m_itemId.getSocketHolder(y).getSocketType() + " Socket " + l_report);
                            p_renderer.setIcon(CGemType.getGemImage(m_itemId.getSocketHolder(y).getSocketType()));
                            p_renderer.setBackground(m_metaBrokenColor);
                        }
                        else
                        {
                            p_renderer.setText(m_itemId.getSocketHolder(y).getSocketType() + " Socket");
                            p_renderer.setIcon(CGemType.getGemImage(m_itemId.getSocketHolder(y).getSocketType()));
                            p_renderer.setBackground(Color.WHITE);
                        }
                    }
                    else
                    {
                        p_renderer.setText(m_itemId.getSocketHolder(y).getSocketType() + " Socket");
                        p_renderer.setIcon(CGemType.getGemImage(m_itemId.getSocketHolder(y).getSocketType()));
                        if (!CGemType.matchGem(m_itemId.getSocketHolder(y).getSocketType(),
                                                this.m_gemList.get(y).getGemType()))
                        {
                            p_renderer.setBackground(m_badGemBackground);
                        }
                        else
                        {
                            p_renderer.setBackground(Color.WHITE);
                        }
                    }
                    return;
                }
                else
                {
                    if (this.m_gemList.get(y) != null)
                    {
                        p_renderer.setText(this.m_gemList.get(y).getName() + " " + this.m_gemList.get(y).getItemStats().getNonZeroStatsString());
                        p_renderer.setIcon(CGemType.getGemImage(this.m_gemList.get(y).getGemType()));
                        p_renderer.setBackground(CItemQuality.getBackColor(this.m_gemList.get(y).getGearQuality()));
                        if (this.m_gemList.get(y).getGemType() == GemType.META)
                        {
                            p_renderer.setToolTipText("<html>" + this.m_gemList.get(y).getHtmlTooltip() + "</html>");
                        }
                        return;
                    }
                }
            }
        }        
    }

    public int getTotalGems(GemType p_gemType)
    {
        int l_totalGems = 0;
        if (this.m_blacksmith)
        {
            if (CGemType.metaGemCompatible(p_gemType, this.m_blacksmithGem.getGemType()))
            {
                l_totalGems++;
            }
        }

        if (this.m_beltBuckleGem != null)
        {
            if (CGemType.metaGemCompatible(p_gemType, this.m_beltBuckleGem.getGemType()))
            {
                l_totalGems++;
            }
        }

        for (int i = 0; i < this.m_itemId.getNumberOfSockets(); i ++)
        {
            if (CGemType.metaGemCompatible(p_gemType, this.m_gemList.get(i).getGemType()))
            {
                l_totalGems++;
            }
        }

        return l_totalGems;
    }

    public void addXMLData(Element p_root)
    {
        // Need to save slot id, item, gems, enchant, poison
        // Add item id
        Element l_item = p_root.addElement("slot").
                        addAttribute("id", String.valueOf(this.m_itemId.getId())).
                        addAttribute("slottype", this.m_slotType.toString());

        if (this.m_blacksmith)
        {
            l_item.addAttribute("bsgem", String.valueOf(this.m_blacksmithGem.getId()));
        }

        if (this.m_slotType == DollSlotType.WAIST)
        {
            l_item.addAttribute("bbgem", String.valueOf(this.m_beltBuckleGem.getId()));
        }

        if (this.m_enchantable)
        {
            l_item.addAttribute("enchant", String.valueOf(this.m_enchantId.getId()));
        }

        if (this.m_poisonable)
        {
            l_item.addAttribute("poison", String.valueOf(this.m_poisonId.getId()));
        }

        if (this.m_itemId.getNumberOfSockets() != 0)
        {
            // Add gem list
            Element l_sockets = l_item.addElement("itemgems");
            for (int i = 0; i < this.m_itemId.getNumberOfSockets(); i ++)
            {
                l_sockets.addElement("gem").
                            addAttribute("id", String.valueOf(this.m_gemList.get(i).getId()));

            }
        }
    }

    public void parseXMLElement(Element p_element)
    {
        // p_element has our item ptr in it.
        CGlobal.g_paperDoll.setItem(CGlobal.g_database.getItem(p_element.attributeValue("id")), this.m_slotType);
        if (this.m_blacksmith)
        {
            CGlobal.g_paperDoll.setBSGem(CGlobal.g_database.getItem(p_element.attributeValue("bsgem")), this.m_slotType);
        }

        if (this.m_slotType == DollSlotType.WAIST)
        {
            CGlobal.g_paperDoll.setBBGem(CGlobal.g_database.getItem(p_element.attributeValue("bbgem")), this.m_slotType);
        }

        if (this.m_enchantable)
        {
            CGlobal.g_paperDoll.setEnchant(CGlobal.g_database.getItem(p_element.attributeValue("enchant")), this.m_slotType);
        }

        if (this.m_poisonable)
        {
            CGlobal.g_paperDoll.setPoison(CGlobal.g_database.getItem(p_element.attributeValue("poison")), this.m_slotType);
        }

        Node l_node = p_element.selectSingleNode("itemgems");
        if (l_node != null)
        {
            List l_list = l_node.selectNodes( "gem" );
            int l_index = 0;
            for (Iterator l_iter = l_list.iterator(); l_iter.hasNext(); ) {
                Element l_element = (Element) l_iter.next();
                CGlobal.g_paperDoll.setGem(CGlobal.g_database.getItem(l_element.attributeValue("id")), this.m_slotType, l_index++);
            }
        }
    }
}
